package Logic.Objects;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import Conf.Consts;
import Conf.LandBorders;
import Exceptions.MoveException;
import Exceptions.StrategoException;
import Logic.IPlayEngine;
import Logic.IPlayer;
import Logic.IPoint;
import Logic.MoveResults;
import Logic.Square;
import Logic.MoveResults.MoveResultsType;
import Logic.Objects.GameOptions.Aggression;
import Logic.Objects.GameOptions.Blitzkrieg;
import Logic.Objects.GameOptions.BoardVisibility;
import Logic.Objects.GameOptions.BombsExplosion;
import Logic.Objects.GameOptions.BombsReuse;
import Logic.Objects.GameOptions.FightVisibility;
import Logic.Objects.GameOptions.FlagCapture;
import Logic.Objects.GameOptions.MovableFlag;
import Logic.Objects.GameOptions.VisibleFlag;
import Logic.Square.Rank;
import Logic.Square.Type;

public class PlayEngine implements IPlayEngine{
	private static final long TIMEOUT = 20000;
	private Integer numberOfPlayers;
	private Integer currentPlayer = 1;
	// each move, update this object. the object save the last state of the engine
	PlayEngineState engineState = new PlayEngineState();
	// when player lose, this object is updated to score the player
	// remember the current score - when player die, he get the currScore and increase it by 1
	private Integer currScore = 0;
	private ArrayList<Player> players;
	private Integer boardWidth;
	private Integer boardHeight;
	private ArrayList<Square> boardSquares;
	private GameOptions gameOptions = new GameOptions();
	private Long engineNumber;
	private LinkedList<MoveResults> lastMoves = new LinkedList<MoveResults>();
	private long[] lastContact;	
	private Vector<IPlayer> loserPlayers = new Vector<IPlayer>();

	public GameOptions getGameOptions() {
		return gameOptions;
	}

	public void setGameOptions(GameOptions gameOptions) {
		this.gameOptions = gameOptions;
	}

	public void setBoard(int width, int height) {
		this.boardWidth = width;
		this.boardHeight = height;

		boardSquares = new ArrayList<Square>(width*height);
		for (int i=0; i<height*width; i++) {
			boardSquares.add(GameFactory.createFreeSquare());
		}
		ScatterWaterOnBoard();	
	}

	public PlayEngine(IPlayEngine src) throws StrategoException {
		this.clone(src);
	}

	public PlayEngine(){}

	public MoveResults move(Move move) throws MoveException {
		return move(move.old_x,move.old_y,move.new_x,move.new_y);
	}

	public MoveResults move(int x1, int y1, int x2, int y2) throws MoveException {
		Square square1 = getBoardXY(x1, y1);
		Square square2 = getBoardXY(x2, y2);
		IPoint p1 = new Point(x1,y1);
		IPoint p2 = new Point(x2,y2);

		//you cannot move a square that is not a soldier
		if (square1==null || square1.getType()!=Type.Soldier) {
			throw new MoveException(MoveException.MoveExceptionType.NotValidStartSquare);
		}

		Square soldier = (Square) square1;
		if (soldier.getPlayerId() != getCurrentPlayer(-1)) {
			throw new MoveException(MoveException.MoveExceptionType.NotYourSoldier);
		}

		//you can only move to a walkable square
		if (square2==null || !square2.isWalkable()) {
			throw new MoveException(MoveException.MoveExceptionType.NotValidEndSquare);
		}

		//distances should be 1 and 0
		int hDistance = Math.abs(x2-x1);
		int vDistance = Math.abs(y2-y1);

		if (soldier.getRank() == Rank.Scout) {
			if (hDistance*vDistance!=0 || hDistance+vDistance==0) {
				throw new MoveException(MoveException.MoveExceptionType.NotValidDistance);
			}
		} else if (soldier.getRank() == Rank.Bomb) {
			throw new MoveException(MoveException.MoveExceptionType.BombCantMove);
		} else if (gameOptions.getMovableFlag().equals(MovableFlag.Off) && soldier.getRank() == Rank.Flag) {
			throw new MoveException(MoveException.MoveExceptionType.FlagCantMove);
		} else {
			if (hDistance+vDistance!=1) {
				throw new MoveException(MoveException.MoveExceptionType.NotValidDistance);
			}
		}

		engineState.savePreState(this,p1, p2);

		MoveResults result = null;
		if (square2.getType() == Type.Soldier) {
			result = fight(x1, y1, x2, y2);

		} else if (square2.getType() == Type.Free) {
			setBoardXY(square1, x2, y2);
			setBoardXY(square2, x1, y1);

			result = new MoveResults(MoveResultsType.move,x1,y1,x2,y2);
			result.setSoldier(soldier);
		}

		// This shouldn't happen
		if (result == null) throw new MoveException(MoveException.MoveExceptionType.Unknown);

		switch (result.getType())
		{
		case move:
			getPlayer(currentPlayer).setLastEvent(MoveResultsType.move);
			break;
		case lose:
			getPlayer(currentPlayer).setLastEvent(MoveResultsType.lose);
			getPlayer(square2.getPlayerId()).setLastEvent(MoveResultsType.win);
			break;
		case win:
			getPlayer(currentPlayer).setLastEvent(MoveResultsType.win);
			getPlayer(square2.getPlayerId()).setLastEvent(MoveResultsType.lose);
			break;
		case tie:
			getPlayer(currentPlayer).setLastEvent(MoveResultsType.lose);
			getPlayer(square2.getPlayerId()).setLastEvent(MoveResultsType.lose);
			
		}
		
		setNextPlayer(result);
		updateLastMoves(result);
		
		

		return result;
	}

	private void updateLastMoves(MoveResults result) {
		lastMoves.add(result);
		if (lastMoves.size() > 8) {
			lastMoves.poll();
		}
	}

	private void setNextPlayer(MoveResults result) {
		//in case blitzkrieg flag is on and the player won, it's still his turn
		if ((getGameOptions().getBlitzkrieg().equals(Blitzkrieg.Off)) || !result.getType().equals(MoveResults.MoveResultsType.win)) {
			currentPlayer++;
			if (currentPlayer > numberOfPlayers) currentPlayer = 1;

			while (!players.get(currentPlayer-1).isAlive()) {
				currentPlayer++;
				if (currentPlayer > numberOfPlayers) currentPlayer = 1;
			}
		}
	}

	private MoveResults fight(int x1, int y1, int x2, int y2) throws MoveException {
		Square soldier1 = (Square) getBoardXY(x1, y1);
		Square soldier2 = (Square) getBoardXY(x2, y2);
		MoveResults result;
		if (soldier1.getPlayerId() == soldier2.getPlayerId()) {
			throw new MoveException(MoveException.MoveExceptionType.CantAttackOwnSoldier);
		}

		if (soldier2.getRank() == Rank.Bomb) {// Bomb was attacked
			if (soldier1.getRank() == Rank.Miner) {
				result = new MoveResults(MoveResultsType.win,x1,y1,x2,y2);
			} else {
				result = new MoveResults(MoveResultsType.lose,x1,y1,x2,y2);
			}
		} else if (soldier1.getRank() == Rank.Spy && soldier2.getRank() == Rank.Marshal) {
			result = new MoveResults(MoveResultsType.win,x1,y1,x2,y2);
		} else if (soldier2.getRank() == Rank.Flag) { // Flag
			result = new MoveResults(MoveResultsType.win,x1,y1,x2,y2);
			eliminatePlayer(soldier2.getPlayerId(), soldier1.getPlayerId());			
		} else if (soldier1.getRank().getId() > soldier2.getRank().getId()) {		// Regular Fight
			result = new MoveResults(MoveResultsType.win,x1,y1,x2,y2);
		} else if (soldier1.getRank().getId() == soldier2.getRank().getId()) {
			if (getGameOptions().getAggression().equals(Aggression.BothDead)) {
				result = new MoveResults(MoveResultsType.tie,x1,y1,x2,y2);
			} else {
				result = new MoveResults(MoveResultsType.win,x1,y1,x2,y2);
			}
		} else {
			result = new MoveResults(MoveResultsType.lose,x1,y1,x2,y2);
		}

		result.setSoldiers(soldier1.duplicateInstance(),soldier2.duplicateInstance());

		switch (result.getType()) {
		case win:
			setBoardXY(GameFactory.createFreeSquare(), x1, y1);
			setBoardXY(soldier1, x2, y2);
			break;
		case lose:
			setBoardXY(GameFactory.createFreeSquare(), x1, y1);
			if (soldier2.getRank().equals(Rank.Bomb)) {
				if (getGameOptions().getBombReuse().equals(BombsReuse.OneTime)) {
					setBoardXY(GameFactory.createFreeSquare(), x2, y2);
				}
				if (getGameOptions().getBombsExplosion().equals(BombsExplosion.Big)) {
					if (getBoardXY(x2-1, y2) != null && getBoardXY(x2-1, y2).getType().equals(Square.Type.Soldier)) {
						setBoardXY(GameFactory.createFreeSquare(), x2-1, y2);
					}
					if (getBoardXY(x2, y2-1) != null && getBoardXY(x2, y2-1).getType().equals(Square.Type.Soldier)) {
						setBoardXY(GameFactory.createFreeSquare(), x2, y2-1);
					}
					if (getBoardXY(x2+1, y2) != null && getBoardXY(x2+1, y2).getType().equals(Square.Type.Soldier)) {
						setBoardXY(GameFactory.createFreeSquare(), x2+1, y2);
					}
					if (getBoardXY(x2, y2+1) != null && getBoardXY(x2, y2+1).getType().equals(Square.Type.Soldier)) {
						setBoardXY(GameFactory.createFreeSquare(), x2, y2+1);
					}
				}
			}
			break;
		case tie:
			setBoardXY(GameFactory.createFreeSquare(), x1, y1);
			setBoardXY(GameFactory.createFreeSquare(), x2, y2);
			break;
		}
		return result;
	}

	private void eliminatePlayer(int playerId, int killerId) {
		if ( (playerId>=1) && (playerId<=numberOfPlayers) ) {
			players.get(playerId-1).killPlayer();
			for (Square square : boardSquares) {
				if (square.getPlayerId() == playerId) {
					if (getGameOptions().getFlagCapture().equals(FlagCapture.SoldiersDie)) {
						square.setFree();	
					}
					else {
						square.setPlayerId(killerId);
					}
				}
			}
			try {
				if (players.get(playerId-1).isHuman()){
					ScoreBoard.addNewScore( players.get(playerId-1), currScore++,loserPlayers);
					// add the eliminated player
					loserPlayers.add(players.get(playerId-1));
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}	

	public void setCurrentPlayer(Integer currentPlayer) {
		this.currentPlayer = currentPlayer;
	}

	/*
	 * We use the getCurrentPlayer method as a way to make sure that
	 * all players are still online. for every request of getCurrentPlayer
	 * we update the last contact time to be now. also we check the 
	 * last contact time for all the players
	 * 
	 * playerId == -1 means you don't need to update or check the last contacts
	 */

	public int getCurrentPlayer(int playerId) {
		if (playerId != -1) {
			lastContact[playerId-1] = System.currentTimeMillis();

			for (int i = 0; i < getNumberOfPlayers(); i++) {
				if (getPlayer(i+1).isHuman() && System.currentTimeMillis()-lastContact[i] > TIMEOUT) {
					getPlayer(i+1).setAI();
				}
			}
		}

		return currentPlayer;
	}

	public void setNumberOfPlayers(int numberOfPlayers) {
		this.numberOfPlayers = numberOfPlayers;
		this.currentPlayer = 1;

		this.players = new ArrayList<Player>(numberOfPlayers);
		this.lastContact = new long[numberOfPlayers];
		for (int i=0; i<numberOfPlayers; i++)
		{
			Player p = new Player("",Player.Type.human,i+1);
			players.add(p);
			lastContact[i] = System.currentTimeMillis();
		}
	}

	public int getNumberOfPlayers() {
		return numberOfPlayers;
	}


	public boolean isGameOver() {
		int count = 0;
		boolean humanInGame = false;
		for (int i = 0; i < numberOfPlayers; i++) {
			if (players.get(i).isHuman()) humanInGame = true;
			if (players.get(i).isAlive()) count++;
		}
		
		boolean gameOver = (count <= 1 || !humanInGame);
		
		if (gameOver) {
			// TODO: Save match results to score board
		}
		
		return gameOver;
	}

	// do we need this ?
	public boolean[] getAlivePlayers() {
		boolean[] alive = new boolean[numberOfPlayers];
		for (int i=0;i<numberOfPlayers;i++)
		{
			alive[i] = players.get(i).isAlive();
		}
		return alive;
	}

	public void clone(IPlayEngine src) throws StrategoException {
		//deep cloning
		setBoard(src.getBoardWidth(), src.getBoardHeight());
		for (int j=1;j<=src.getBoardHeight();j++)
			for (int i=1;i<=src.getBoardWidth();i++)
			{
				this.setBoardXY(src.getBoardXY(i, j), i, j);
			}

		this.numberOfPlayers = src.getNumberOfPlayers();
		this.currentPlayer = src.getCurrentPlayer(-1);
		players = new ArrayList<Player>(numberOfPlayers);
		for (int i=0;i<numberOfPlayers;i++)
		{
			players.add(new Player("",IPlayer.Type.human,i+1));
			players.get(i).clone(src.getPlayer(i+1));
		}


	}
	public Player getPlayer(int i)
	{
		if ( (i>=1) && (i<=numberOfPlayers) )
			return players.get(i-1);

		return null;
	}
	public void undo(){
		engineState.undo(this);
	}

	public void redo(){
		engineState.redo(this);
	}


	public String getPlayerName(int playerNum) {
		if ( (playerNum>=1) && (playerNum<=numberOfPlayers) ) {
			String name = players.get(playerNum-1).getName();
			return name;
		} else {
			return null;
		}
	}

	public int getPlayerID(String playerName) {
		for (int i=0;i<players.size();i++){
			if (players.get(i).getName().equals(playerName))
				return players.get(i).getID();
		}	 
		return -1;
	}


	public void setPlayerName(int playerNum, String name) {
		if ( (playerNum>=0) && (playerNum<=numberOfPlayers) )
			players.get(playerNum-1).setName(name);
	}

	public void setAIPlayer(int playerNum) {
		if ( (playerNum>=1) && (playerNum<=numberOfPlayers) )
			players.get(playerNum-1).setAI();

	}

	public void setHumanPlayer(int playerNum) {
		if ( (playerNum>=1) && (playerNum<=numberOfPlayers) )
			players.get(playerNum-1).setHuman();

	}

	public Long getEngineNumber() {
		return engineNumber;
	}

	public void setEngineNumber(long engineNum) {
		engineNumber=engineNum;

	}

	public List<Square> getAllBoard() {
		return boardSquares;
	}


	public Square getBoardXY(int x, int y) {
		if (!(x<=boardWidth && x>=1 && y<=boardHeight && y>=1)) {
			return null;
		}
		return boardSquares.get((x-1)+boardWidth*(y-1));
	}


	public boolean setBoardXY(Square square, int x, int y) {
		if (!(x<=boardWidth && x>=1 && y<=boardHeight && y>=1)) {
			return false;
		}
		boardSquares.set((x-1)+boardWidth*(y-1),square);
		return true;
	}


	public int getBoardWidth() {
		return boardWidth;
	}

	public int getBoardHeight() {
		return boardHeight;
	}

	private void ScatterWaterOnBoard(){
		for(int j=0 ; j < Consts.WaterNumber; j++) {
			IPoint pWatter  = RandomllyScatterWatter ();
			setBoardXY(GameFactory.createWaterSquare(), pWatter.getX(), pWatter.getY());
		}
	}

	/*
	 * RandomllyScatterWatter:
	 * Random Search for available water point.
	 * 
	 * @ return IPoint of water.
	 */
	private IPoint RandomllyScatterWatter (){
		boolean runFlag = true;
		int x=-1;
		int y=-1;
		while (runFlag)  {
			x = (int)(Math.random() *100 );
			x%=Consts.N;
			x++;
			y = (int)(Math.random() *100);
			y%=Consts.N;
			y++;
			boolean PlayeFlag = false;
			for (int i=1;i<Consts.MaxNumberOfPlayers+1;i++){				
				if(LandBorders.CheckPlayerBorders(i, x, y)) {
					PlayeFlag=true;
					i=Consts.MaxNumberOfPlayers+1;
				}
			}
			if (!PlayeFlag)
				runFlag = false;
		}
		if (x!=-1 && y!=-1)
			return new Point(x,y);
		return null;	
	}

	/*
	 * SetMySoldiersRandomlly:
	 * Scatter player soldiers on board with in player Land Borders.
	 * 
	 */
	public void SetMySoldiersRandomlly(int PlayerNum) throws StrategoException {
		int type_list_index=-1;
		List<Integer> list = new LinkedList<Integer>();
		IPoint[] PlayerLandBorders = LandBorders.getBorders(PlayerNum);
		SoldiersAmountCounter Sam = new SoldiersAmountCounter();
		for (int i=1;i<13;i++)
			list.add(i);
		for (int i=0,x=PlayerLandBorders[0].getX(),y=PlayerLandBorders[0].getY(); i<Consts.NumOfSquersPerPlayer; i++) {
			Random generator=new Random();
			int type=-1;
			//randomize soldier type, so you wont have to make it manually
			type_list_index=generator.nextInt(list.size());
			type=list.get(type_list_index);
			Square Soldier = SelectSoldier(PlayerNum,type,Sam);
			if (Soldier==null) {
				list.remove(type_list_index);
				i--;
				continue;
			}
			setBoardXY(Soldier,x,y);
			if (y < LandBorders.MaxY(PlayerNum))
				y++;
			else 
			{
				y=PlayerLandBorders[0].getY();
				if (x < LandBorders.MaxX(PlayerNum)) 
					x++;
			}		
		}	
	}

	public void strSetMySoldiersRandomlly(String PlayerName) throws StrategoException {
		int PlayerNum = getPlayerID(PlayerName);
		SetMySoldiersRandomlly(PlayerNum);
	}

	/*
	 * SelectSoldier:
	 * Check is number of Soldier of Rank "type" is < number of "type" allowed
	 * and if (true) return ISquare of Rank "type".
	 * 
	 * @return ISquare .
	 */
	private Square SelectSoldier(int PlayerNum,int type, SoldiersAmountCounter Sam) throws StrategoException {
		Square Soldier = null;
		switch (type) {
		case 1: 
			if (Sam.Marshal<Consts.SoldiersAmount.Marshal.getAmount()) 
			{
				Sam.Marshal ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Marshal);
			}
			else 
			{
				return null;
			}
			break;
		case 2: 
			if (Sam.General<Consts.SoldiersAmount.General.getAmount()) 
			{
				Sam.General ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.General);
			}
			else 
			{
				return null;
			}
			break;
		case 3: 
			if (Sam.Colonel<Consts.SoldiersAmount.Colonel.getAmount()) 
			{
				Sam.Colonel ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Colonel);
			}
			else 
			{			    	
				return null;
			}
			break;
		case 4: 
			if (Sam.Major<Consts.SoldiersAmount.Major.getAmount()) 
			{
				Sam.Major ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Major);
			}
			else 
			{			    	
				return null;
			}
			break;
		case 5: 
			if (Sam.Captain<Consts.SoldiersAmount.Captain.getAmount()) 
			{
				Sam.Captain ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Captain);
			}
			else 
			{			    	
				return null;
			}
			break;
		case 6: 
			if (Sam.Lieutenant<Consts.SoldiersAmount.Lieutenant.getAmount()) 
			{
				Sam.Lieutenant ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Lieutenant);
			}
			else 
			{			    	
				return null;
			}
			break;
		case 7: 
			if (Sam.Sergeant<Consts.SoldiersAmount.Sergeant.getAmount()) 
			{
				Sam.Sergeant ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Sergeant);
			}
			else 
			{			    	
				return null;
			}
			break;
		case 8: 
			if (Sam.Miner<Consts.SoldiersAmount.Miner.getAmount()) 
			{
				Sam.Miner ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Miner);
			}
			else 
			{
				return null;
			}
			break;
		case 9: 
			if (Sam.Scout<Consts.SoldiersAmount.Scout.getAmount()) 
			{
				Sam.Scout ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Scout);
			}
			else 
			{
				return null;
			}
			break;
		case 10: 
			if (Sam.Spy<Consts.SoldiersAmount.Spy.getAmount()) 
			{
				Sam.Spy ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Spy);
			}
			else 
			{
				return null;
			}
			break;
		case 11: 
			if (Sam.Bomb<Consts.SoldiersAmount.Bomb.getAmount()) 
			{
				Sam.Bomb ++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Bomb);
			}
			else 
			{
				return null;
			}
			break;
		case 12: 
			if (Sam.Flag<Consts.SoldiersAmount.Flag.getAmount()) 
			{
				Sam.Flag++;
				Soldier = GameFactory.createSoldierSquare(PlayerNum, Rank.Flag);
			}
			else 
			{
				return null;
			}
			break;
		}
		return Soldier;
	}

	@Override
	public Square[][] getDisplayForPlayer(int playerId)
	throws StrategoException {
		Square[][] display = new Square[getBoardWidth()][getBoardHeight()];
		int x = 0;
		int y = 0;
		for (Square square : boardSquares) {
			if ((square.getType().equals(Square.Type.Soldier)) && (square.getPlayerId() != playerId)) {
				if (getGameOptions().getBoardVisibility().equals(BoardVisibility.VisibleToAll)) {
					display[x][y] = square;
				} else if (square.getRank().equals(Rank.Flag) && (getGameOptions().getVisibleFlag().equals(VisibleFlag.On))) {
					display[x][y] = square;
				} else {
					display[x][y] = GameFactory.createSoldierSquare(square.getPlayerId(), Rank.Unknown);
				}
			} else {
				display[x][y] = square;
			}

			x++;
			if (x >= getBoardWidth()) {
				y++;
				x = 0;
			}
		}
		return display;
	}

	public List<MoveResults> getLastMoves(int turns) {
		return getLastMovesForPlayer(turns, -1);
	}

	public List<MoveResults> getLastMovesForPlayer(int turns, int playerId) {
		List<MoveResults> list = new LinkedList<MoveResults>();

		for (int i  = 1; i <= Math.min(lastMoves.size(),turns); i++) {
			MoveResults move = lastMoves.get(lastMoves.size()-i);

			if (playerId != -1 && getGameOptions().getFightVisibility() == FightVisibility.OnlyFighters &&
					playerId != move.getSoldier1().getPlayerId() && playerId != move.getSoldier2().getPlayerId()) {

				MoveResults newMove = new MoveResults(move.getType(), move.getX1(), move.getY1(), move.getX2(), move.getY2());
				newMove.setSoldiers(move.getSoldier1(), move.getSoldier2());
				newMove.getSoldier1().setRank(Rank.Unknown);
				newMove.getSoldier2().setRank(Rank.Unknown);

				list.add(newMove);
			} else {
				list.add(move);
			}
		}

		return list;
	}

	@Override
	public void clearLastMoves() {
		lastMoves.clear();
	}

	@Override
	public Object[] getCurrentPlayer_And_Display_And_LastMovesForPlayer(int turns, int playerId) throws StrategoException {
		Object[] res = new Object[3];
		res[0] = getDisplayForPlayer(playerId);
		res[1] = getLastMovesForPlayer(turns, playerId);
		res[2] = getCurrentPlayer(playerId);
		return res;
	}

	@Override
	public MoveResults playAI() throws StrategoException {
		Player curPlayer = getPlayer(getCurrentPlayer(-1));
		if (!curPlayer.isHuman()) {
			Move move = curPlayer.AIGenerateNextMove(getDisplayForPlayer(currentPlayer));

			MoveResults result = move(move);
			return result;
		}
		return null;
	}

	@Override
	public Player[] getAllPlayers() {
		Player[] allPlayers = new Player[getNumberOfPlayers()];
		players.toArray(allPlayers);
		return allPlayers;
	}

	@Override
	public void leaveGame(int playerId) {
		getPlayer(playerId-1).setAI();
		isGameOver();
	}
}
